package firbi.base;

import java.util.Random;

import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.ListView;
import android.widget.TextView;
import firbi.base.util.Constants;

/**
 * Instrumentation test case for RouteView.
 * Tests the menu and the sort function.
 * @author Kathryn Winglee
 *
 */

public class RouteViewTest_Functional extends
		ActivityInstrumentationTestCase2<RouteView> {
	private RouteView mRouteView;
	private Intent mStartIntent;
	private Instrumentation.ActivityMonitor mMonitorSearch;
	private Instrumentation.ActivityMonitor mMonitorFav;
	private Instrumentation.ActivityMonitor mMonitorDest;
	private Instrumentation.ActivityMonitor mMonitorStop;
	private String mDest = "Downtown";
	private String mRoute = "0001_12";
	private String mRouteNum = "12";
	private double mLat = 47.6198;
	private double mLong = -122.347;
	
	/**
	 * Constructs the class
	 */
	public RouteViewTest_Functional() {
		super("firbi.base", RouteView.class);
	}    
	
	/**
	 * Set up the intent and call the class with a destination and route.
	 */
	@Override
	protected void setUp() throws Exception {
		super.setUp();
		
		mStartIntent = new Intent(Intent.ACTION_MAIN);
	}
	
	/**
	 * Sets mRouteView and mStartIntent to null.
	 */
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
		mRouteView = null;
		mStartIntent = null;
	}
	
	/**
	 * Tests that each item in the menu sends the correct intent and that
	 * clicking on the list goes to StopView.
	 * @throws InteruptedException from threading
	 */
	@SmallTest
	public void testClick() throws Exception{
		
		mMonitorSearch = new Instrumentation.ActivityMonitor("firbi.base.Search", null, true);
		mMonitorFav = new Instrumentation.ActivityMonitor("firbi.base.Favorites", null, true);
		mMonitorStop = new Instrumentation.ActivityMonitor("firbi.base.StopView", null, true);
		this.getInstrumentation().addMonitor(mMonitorSearch);
    	this.getInstrumentation().addMonitor(mMonitorFav);
    	this.getInstrumentation().addMonitor(mMonitorStop);
    	
    	mStartIntent.putExtra(Constants.sROUTE_KEY, mRoute);
		mStartIntent.putExtra(Constants.sDEST_KEY, mDest);
		this.setActivityIntent(mStartIntent);
		mRouteView = this.getActivity();
		while(!RouteView.isThreadDone());
		assertNotNull(mRouteView);
		Thread.sleep(1000);
    	
		/* Test the header is correct */
		TextView rnumber =(TextView) mRouteView.findViewById(R.id.route);
		assertNotNull(rnumber);
		assertEquals("route number displayed incorrectly", rnumber.getText(), mRouteNum);
		TextView dest = (TextView) mRouteView.findViewById(R.id.destination);
		assertNotNull(dest);
		assertEquals("route destination displayed incorrectly", dest.getText(), mDest);
 	    
 	    /* Test if menu goes to favorites*/
 	    assertEquals("Has been to favorites", 0, mMonitorFav.getHits());
    	sendKeys(KeyEvent.KEYCODE_MENU);
 	    sendKeys(KeyEvent.KEYCODE_DPAD_UP);
 	    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
 	    sendKeys(KeyEvent.KEYCODE_ENTER);
    	Thread.sleep(3000);
    	assertEquals("Went to favorites", 1, mMonitorFav.getHits());
		
		/* Test the list */
		ListView list = mRouteView.getListView();
		Random generator = new Random();
		int r = generator.nextInt(list.getCount());
		assertEquals("route clicked", 0, mMonitorStop.getHits());
		mRouteView.onListItemClick(list, mRouteView.getCurrentFocus(), r, r);
		assertEquals("route clicked", 1, mMonitorStop.getHits());
		
	}
	
	/**
	 * Tests pushing the GPS button when GPS is or is not enabled.
	 * @throws InterruptedException 
	 */
	@SmallTest
	public void testGPSButton() throws InterruptedException {
		mStartIntent.putExtra(Constants.sROUTE_KEY, mRoute);
		mStartIntent.putExtra(Constants.sDEST_KEY, mDest);
		this.setActivityIntent(mStartIntent);
		mRouteView = this.getActivity();
		while(!RouteView.isThreadDone());
		assertNotNull(mRouteView);
 	    
 	    /*gps on*/
    	Location loc = new Location(LocationManager.GPS_PROVIDER);
		loc.setTime(System.currentTimeMillis());
		LocationManager locMan = (LocationManager)mRouteView.getSystemService(Context.LOCATION_SERVICE);
    	locMan.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true);
    	locMan.setTestProviderLocation(LocationManager.GPS_PROVIDER, loc);
		loc.setLatitude(mLat);
		loc.setLongitude(mLong);
		Thread.sleep(2000);
 	    sendKeys(KeyEvent.KEYCODE_DPAD_UP);
 	    sendKeys(KeyEvent.KEYCODE_DPAD_UP);
 	    sendKeys(KeyEvent.KEYCODE_ENTER);
		
    }
	
	/**
	 * Tests passing in a gps coordinate.
	 * @throws InterruptedException
	 */
	@SmallTest
	public void testGPSIn() throws InterruptedException {
		mStartIntent.putExtra(Constants.sROUTE_KEY, mRoute);
		mStartIntent.putExtra(Constants.sDEST_KEY, mDest);
		mStartIntent.putExtra(Constants.sROUTE_LAT_KEY, mLat);
		mStartIntent.putExtra(Constants.sROUTE_LON_KEY, mLong);
		this.setActivityIntent(mStartIntent);
		mRouteView = this.getActivity();
		while(!RouteView.isThreadDone());
		assertNotNull(mRouteView);
		Thread.sleep(2000);
		
		ListView list = mRouteView.getListView();
 	    TextView col =(TextView) list.getChildAt(0).findViewById(R.id.distanceCol);
		assertNotNull("gps off has distance column", col);
	}

	/**
	 * Tests passing an intent with no destination. All other tests
	 * have a destination passed in.
	 */
	@SmallTest
	public void testNoDest() {
		mMonitorDest = new Instrumentation.ActivityMonitor("firbi.base.DestinationView", null, true);
		this.getInstrumentation().addMonitor(mMonitorDest);
		
		assertEquals("Went to destination", 0, mMonitorDest.getHits());
		mStartIntent.putExtra(Constants.sROUTE_KEY, mRoute);
		this.setActivityIntent(mStartIntent);
		mRouteView = this.getActivity();
		while(!RouteView.isThreadDone());
		assertNotNull(mRouteView);;
		
		assertEquals("Went to destination", 1, mMonitorDest.getHits());
	}
	
	/**
	 * Tests passing an intent with an incorrect destination (a string that is not a destination
	 * for the route). RouteView should just display an empty list.
	 */
	@SmallTest
	public void testBadDest() {
		long start = System.nanoTime();
		
    	mStartIntent.putExtra(Constants.sROUTE_KEY, mRoute);
		mStartIntent.putExtra(Constants.sDEST_KEY, "111");
		this.setActivityIntent(mStartIntent);
		mRouteView = this.getActivity();
		while(!RouteView.isThreadDone());
		assertNotNull(mRouteView);

		Log.i("route", "testBadDest after while "+(System.nanoTime() - start));
		
		ListView list = mRouteView.getListView();
		assertEquals(0, list.getCount());
		Log.i("route", "testBadDest "+(System.nanoTime() - start));
	}
	
	/**
	 * Tests the case when no route is passed in the intent. All other tests
	 * have the route id passed in.
	 * 
	 * @throws Exception
	 */
	@SmallTest
	public void testNoRoute() throws Exception {
		mStartIntent.putExtra(Constants.sDEST_KEY, mDest);
		this.setActivityIntent(mStartIntent);
		mRouteView = this.getActivity();
		while(!RouteView.isThreadDone());
		assertNotNull(mRouteView);
		Thread.sleep(40);
		
		ListView list = mRouteView.getListView();
		assertEquals(0, list.getCount());
	}

	/**
	 * Tests the case when an incorrect route id is passed in the intent. All other
	 * tests have a correct route id passed in.
	 * 
	 * @throws Exception
	 */
	@SmallTest
	public void testBadRoute() throws Exception {
		mStartIntent.putExtra(Constants.sROUTE_KEY, "abc");
		mStartIntent.putExtra(Constants.sDEST_KEY, mDest);
		this.setActivityIntent(mStartIntent);
		mRouteView = this.getActivity();
		while(!RouteView.isThreadDone());
		assertNotNull(mRouteView);

		ListView list = mRouteView.getListView();
		assertEquals(0, list.getCount());
	}

	/**
	 * Tests the sorting function in RouteView.
	 */
	@SmallTest
	public void testSort() {
		mStartIntent.putExtra(Constants.sROUTE_KEY, mRoute);
		mStartIntent.putExtra(Constants.sDEST_KEY, mDest);
		this.setActivityIntent(mStartIntent);
		mRouteView = this.getActivity();
		while(!RouteView.isThreadDone());
		assertNotNull(mRouteView);
		
		/* null array */
		double[] test = null;
		mRouteView.sort(test);
		assertNull("null array", test);
		
		/* length 0 array */
		test = new double[0];
		mRouteView.sort(test);
		assertEquals("0 length array", test.length, 0);
		
		/* length 1 array */
		test = new double[1];
		mRouteView.sort(test);
		test[0] = 1;
		
		/* array already ordered */
		test = new double[10];
		for(int i = 0; i < test.length; i++) {
			test[i] = i;
		}
		mRouteView.sort(test);
		for(int i = 0; i < test.length; i++) {
			assertEquals("sorted array", (double) i, test[i]);
		}
		test = new double[13];
		for(int i = 0; i < test.length; i++) {
			test[i] = i;
		}
		mRouteView.sort(test);
		for(int i = 0; i < test.length; i++) {
			assertEquals("sorted array", (double) i, test[i]);
		}
		
		/* array ordered backwards */
		test = new double[10];
		for(int i = 0; i < test.length; i++) {
			test[i] = test.length - i;
		}
		mRouteView.sort(test);
		for(int i = 0; i < test.length; i++) {
			assertEquals("backward array", (double)i+1, test[i]);
		}
		test = new double[13];
		for(int i = 0; i < test.length; i++) {
			test[i] = test.length - i;
		}
		mRouteView.sort(test);
		for(int i = 0; i < test.length; i++) {
			assertEquals("backward array", (double)i+1, test[i]);
		}
		
		/* random array */
		ListView list = mRouteView.getListView();
		Random generator = new Random();
		int len = list.getCount();
		test = new double[len];
		for(int j =0; j < len; j++) {
			test[j] = generator.nextDouble()*generator.nextInt();
		}
		mRouteView.sort(test);
		for(int j = 1; j < len; j++) {
			assertTrue("random array", test[j] >= test[j-1]);
		}
	}
	
}

